package com.starleague.battletech.unit.mech.jpa.appengine;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Transient;

import com.starleague.battletech.unit.jpa.appengine.BattletechUnitHitLocationGae;
import com.starleague.battletech.unit.mech.IMechActuator;
import com.starleague.battletech.unit.mech.IMechHitLocationArm;
import com.starleague.battletech.unit.mech.IMechHitLocationCenterTorso;
import com.starleague.battletech.unit.mech.IMechHitLocationHead;
import com.starleague.battletech.unit.mech.IMechHitLocationLeg;
import com.starleague.battletech.unit.mech.IMechHitLocationSideTorso;
import com.starleague.battletech.unit.mech.MechHitLocationPosition;
import com.starleague.battletech.unit.mech.jpa.appengine.MechCoreComponentGae;

@Entity(name = "MECH_HIT_LOCATION")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class MechHitLocationGae
        extends BattletechUnitHitLocationGae
        implements IMechHitLocationHead, IMechHitLocationCenterTorso, IMechHitLocationSideTorso, IMechHitLocationArm,
        IMechHitLocationLeg
{
    // Remember, AppEngine doesn't support FetchType.EAGER / Joins
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    private MechGae mech;

    @Basic(optional = false)
    @Column(nullable = false)
    @Enumerated(EnumType.STRING)
    private MechHitLocationPosition position;

    @OneToMany(mappedBy = "hitLocation", cascade = CascadeType.ALL)
    private List<MechCoreComponentGae> coreComponents;

    MechHitLocationGae(MechGae mech,
                       MechHitLocationPosition position,
                       int armorHitPoints,
                       int internalStructureHitPoints)
    {
        super(armorHitPoints, internalStructureHitPoints);
        this.mech = mech;
        this.position = position;
        this.coreComponents = new ArrayList<>();
    }

    protected MechHitLocationGae()
    {
        //
    }

    @Override
    public MechGae getMech()
    {
        return this.mech;
    }

    @Override
    public MechHitLocationPosition getPosition()
    {
        return this.position;
    }

    // TODO: Somehow get rid of this, via @Access(FIELD) or something...
    protected void setPosition(MechHitLocationPosition position)
    {
        this.position = position;
    }

    List<MechCoreComponentGae> getCoreComponents()
    {
        return this.coreComponents;
    }

    //
    // Calculated values
    //

    @Transient
    public MechCriticalSlotGae[] getCriticalSlots()
    {
        return this.mech.getCriticalSlotsFor(this.position);
    }

    @Transient
    @Override
    public Collection<? extends IMechActuator> getActuators()
    {
        List<MechCoreComponentGae> actuatorList = new ArrayList<>();
        for (MechCoreComponentGae coreComponent : this.coreComponents)
        {
            if (coreComponent.getActuatorType() != null)
                actuatorList.add(coreComponent);
        }
        return actuatorList;
    }

    // public MechCoreComponentGae getActuator(MechActuatorType actuatorType)
    // {
    // for (MechCoreComponentGae coreComponent : this.coreComponents)
    // {
    // if (coreComponent.getActuatorType() == actuatorType)
    // return coreComponent;
    // }
    // return null;
    // }

    MechCoreComponentGae getCoreComponent(MechCoreComponentGae.Type coreComponentType)
    {
        for (MechCoreComponentGae coreComponent : this.coreComponents)
        {
            if (coreComponent.getCoreComponentType() == coreComponentType)
                return coreComponent;
        }
        return null;
    }

    @Override
    public Map<String, Object> infoProperties()
    {
        Map<String, Object> infoPropertyMap = super.infoProperties();
        infoPropertyMap.put("position", this.position);
        infoPropertyMap.put("coreComponents", this.coreComponents);
        int index = 0;
        for (MechCriticalSlotGae criticalSlot : getCriticalSlots())
        {
            infoPropertyMap.put("criticalSlot[" + index++ + "]", (criticalSlot != null)
                    ? criticalSlot.toStringSingleLine()
                    : "<Empty>");
        }
        return infoPropertyMap;
    }
}
